/*
 * @Description:
 * @Version: 2.0
 * @Autor: xudongxu
 * @Date: 2019-12-06 13:05:18
 * @LastEditors: xudongxu
 * @LastEditTime: 2019-12-10 22:08:42
 */
#ifndef __MYAPPLICATION_H__
#define __MYAPPLICATION_H__
#include "Poco/FileChannel.h"
#include "Poco/FormattingChannel.h"
#include "Poco/LogFile.h"
#include "Poco/PatternFormatter.h"
#include "Poco/PipeStream.h"
#include "Poco/Poco.h"
#include "Poco/Process.h"
#include "Poco/StreamCopier.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "mytype.hpp"
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <sys/stat.h>
#include <thread>
#include <unistd.h>
using Poco::Process;
using Poco::ProcessHandle;
using namespace Poco;

const std::string CONFIGPATH = "/usr/local/config";
const std::string LOGPATH = "/usr/local/logs";
class MyApplication : public Util::Application {
  public:
    MyApplication() { m_helpRequested = false; }
    void initialize( Application& self );
    void uninitialize();

    void defineOptions( Util::OptionSet& options );
    void handleHelp( const std::string& name, const std::string& value );
    void handleDaemon( const std::string& name, const std::string& value );
    int main( const std::vector<std::string>& args );

  private:
    bool m_helpRequested; //如果传参数进来那么此变量变为 true 在main() 方法就不要做其他的事情直接退出。
    void beDaemon();
};

void MyApplication::initialize( Application& self ) {
    Util::Application::initialize( self ); //帮我们初始化子系统，必须显示的调用。
    //读取配置文件
    Util::Application::loadConfiguration( CONFIGPATH + "/mainapp.json", PRIO_APPLICATION );
    //初始化日志
    Poco::AutoPtr<Poco::Channel> channel;
    {
        AutoPtr<FileChannel> fileChannel( new FileChannel );
        fileChannel->setProperty( "path", LOGPATH + "/mainapp.log" ); //指定日志路径及文件名
        fileChannel->setProperty( "archive", "timestamp" );           //日志文件加时间戳
        fileChannel->setProperty( "rotation", "10 M" );
        Poco::AutoPtr<Poco::PatternFormatter> patternFormatter( new Poco::PatternFormatter() );
        patternFormatter->setProperty( "pattern", "[%Y-%m-%d %H:%M:%S] %s(%l): %t" ); //每条日志时间
        channel = new Poco::FormattingChannel( patternFormatter, fileChannel );       //初始化　Channel
    }
    logger().setChannel( channel );
}

void MyApplication::uninitialize() {
    Util::Application::uninitialize(); //帮我们关闭子系统，必须显示的调用。
}

void MyApplication::defineOptions( Util::OptionSet& options ) {
    Util::Application::defineOptions( options ); //必须调用
    options.addOption( Util::Option( "help", "h", "display help information on command line arguments" )
                           .required( false )
                           .repeatable( false )
                           .callback( Util::OptionCallback<MyApplication>( this, &MyApplication::handleHelp ) ) );
    options.addOption( Util::Option( "daemon", "", "Run application as a daemon." )
                           .required( false )
                           .repeatable( false )
                           .callback( Util::OptionCallback<MyApplication>( this, &MyApplication::handleDaemon ) ) );
}

void MyApplication::handleHelp( const std::string& name, const std::string& value ) {
    m_helpRequested = true;
    Poco::Util::HelpFormatter helpFormatter( options() );
    helpFormatter.format( std::cout );
}

void MyApplication::handleDaemon( const std::string& name, const std::string& value ) { beDaemon(); }

void MyApplication::beDaemon() {
    pid_t pid;
    if ( ( pid = fork() ) < 0 )
        throw SystemException( "cannot fork daemon process" );
    else if ( pid != 0 )
        exit( 0 );

    setsid();
    umask( 0 );

    FILE* fin = freopen( "/dev/null", "r+", stdin );
    if ( !fin )
        throw Poco::OpenFileException( "Cannot attach stdin to /dev/null" );
    FILE* fout = freopen( "/dev/null", "r+", stdout );
    if ( !fout )
        throw Poco::OpenFileException( "Cannot attach stdout to /dev/null" );
    FILE* ferr = freopen( "/dev/null", "r+", stderr );
    if ( !ferr )
        throw Poco::OpenFileException( "Cannot attach stderr to /dev/null" );
}

int MyApplication::main( const std::vector<std::string>& args ) {
    if ( !m_helpRequested ) {
        try {
            std::cout << "this is main no help\n";
            auto camgrp = cameragroups( config() );
            for ( auto& item : camgrp ) {
                std::string cmd( "rtmp-stream-pusher" );
                std::vector<std::string> args;
                args.push_back( item.rtspurl_bgr() );
                args.push_back( item.rtspurl_ir() );
                args.push_back( item.rtmpurl() );
                std::thread t( [&]() {
                    Poco::Pipe errPipe;
                    ProcessHandle ph = Process::launch( cmd, args, 0, 0, &errPipe );
                    logger().information( "开始推流:" + item.comment() + " : " + item.rtmpurl() );
                    Poco::PipeInputStream istr( errPipe );
                    std::ofstream ostr( LOGPATH + "/error.log" );
                    Poco::StreamCopier::copyStream( istr, ostr );
                } );
                t.detach();
            }
        } catch ( Poco::Exception& ex ) {
            logger().error( ex.displayText() );
        }

    } else {
        std::cout << "this is main call help\n";
    }
    return Application::EXIT_OK;
}

#endif